#ifndef CPU_HPP
#define CPU_HPP

#include <QObject>
#include <QMutex>
#include <QMutexLocker>

#include "command.hpp"
#include "watchdog.hpp"
#include "datamemoryorganisation.hpp"
#include "stackmanagement.hpp"

class CPU : public QObject
{
Q_OBJECT
public:

    /**
    * @brief Creates a new instance
    *
    * @fn CPU
    * @param parent
    */
    explicit CPU(DataMemoryOrganisation *dmo, StackManagement *sm, Watchdog *watchdog, QObject *parent = 0);

    CPU(const CPU &other);

    ~CPU();
    /**
    * @brief
    *
    * @fn executeCommand
    * @param command
    */
    int executeCommand(Command *command, int programCounter);

    void reset();

    /**
    * @brief Returns the Runtime as String
    *
    * @fn getRuntime
    * @return int
    */
    QString getRuntimeAsString() const;

    Watchdog *getWatchdog() const;

    DataMemoryOrganisation *getDataMemoryOrganisation() const;

    StackManagement *getStackManagement() const;

    // All functions
    int Command_ADDWF(int argumentDirBit, int argument7Bit) const;
    int Command_ANDWF(int argumentDirBit, int argument7Bit) const;
    int Command_CLRF(int argument7Bit) const;
    int Command_CLRW() const;
    int Command_COMF(int argumentDirBit, int argument7Bit) const;
    int Command_DECF(int argumentDirBit, int argument7Bit) const;
    int Command_DECFSZ(int argumentDirBit, int argument7Bit, int *programcounter) const;
    int Command_INCF(int argumentDirBit, int argument7Bit) const;
    int Command_INCFSZ(int argumentDirBit, int argument7Bit, int *programcounter) const;
    int Command_IORWF(int argumentDirBit, int argument7Bit) const;
    int Command_MOVF(int argumentDirBit, int argument7Bit) const;
    int Command_MOVWF(int argument7Bit) const;
    int Command_NOP() const;
    int Command_RLF(int argumentDirBit, int argument7Bit) const;
    int Command_RRF(int argumentDirBit, int argument7Bit) const;
    int Command_SUBWF(int argumentDirBit, int argument7Bit) const;
    int Command_SWAPF(int argumentDirBit, int argument7Bit) const;
    int Command_XORWF(int argumentDirBit, int argument7Bit) const;
    int Command_BCF(int argument3Bit, int argument7Bit) const;
    int Command_BSF(int argument3Bit, int argument7Bit) const;
    int Command_BTFSC(int argument3Bit, int argument7Bit, int *programcounter) const;
    int Command_BTFSS(int argument3Bit, int argument7Bit, int *programcounter) const;
    int Command_ADDLW(int argument8Bit) const;
    int Command_ANDLW(int argument8Bit) const;
    int Command_CALL(int argument11Bit, int *programcounter) const;
    int Command_CLRWDT() const;
    int Command_GOTO(int argument11Bit, int *programcounter) const;
    int Command_IORLW(int argument8Bit) const;
    int Command_MOVLW(int argument8Bit) const;
    int Command_RETFIE(int *programcounter) const;
    int Command_RETLW(int argument8Bit, int *programcounter) const;
    int Command_RETURN(int *programcounter) const;
    int Command_SLEEP() const;
    int Command_SUBLW(int argument8Bit) const;
    int Command_XORLW(int argument8Bit) const;

private:

    Watchdog *watchdog;
    DataMemoryOrganisation *dataMemoryOrganisation;
    StackManagement *stackManagement;
    int runtime;
    QMutex *mutex;

    void setCarryFlag(int newValue) const;

    void setDigitCarryFlag(int oldValue, int newValue) const;

    void setZeroFlag(int newValue) const;

signals:

public slots:

};

#endif // CPU_HPP
